/** 
* The syntax analyzer for the Gluck grammar 
* 	Authors: 
*		Rezzano Sebastian
*		Bergez Pablo
*/	
%{
	import java.io.*;
	import gluck.lexico.Token;
	import gluck.lexico.Yylex;
	import gluck.lexico.Yytoken;
	import gluck.sintactico.tree.*;
	import gluck.sintactico.symbolTable.SymbolTable;
%}
    

/* Data Types */
%token TYPE 			300
%token INTEGER			301
%token REAL				302
%token STRING			303
%token BOOLEAN			304

/* Constants Types */
%token INTEGER_NUM 		401	 
%token REAL_NUM			402
%token STRING_TEXT		403
%token TRUE 			404
%token FALSE 			405 

/* Functions */
%token FUNCTION 			501 
%token START_OUTPUT_PARAM 	502

/* Control sequence */
%token IF 				601
%token THEN 			602
%token ELSEIF 			603
%token ELSE 			604
%token WHILE 			605
%token LOOP 			606
%token IFQUIT 			607
%token IFNEVER 			608
%token QUIT 			609

/* Comparison Tokens */
%token EQUAL_COMP 		701
%token UNEQUAL_COMP 	702

/* Variables */
%token ID 				801

/* Operator */
%token LOGIC_OP 		901



/* Data Types */
%type <obj> TYPE
%type <obj> INTEGER
%type <obj> REAL
%type <obj> STRING
%type <obj> BOOLEAN

/* Constants Types */
%type <obj> INTEGER_NUM	 
%type <obj> REAL_NUM
%type <obj> STRING_TEXT
%type <obj> TRUE
%type <obj> FALSE 

/* Functions */
%type <obj> FUNCTION 
%type <obj> START_OUTPUT_PARAM

/* Control sequence */
%type <obj> IF
%type <obj> THEN
%type <obj> ELSEIF
%type <obj> ELSE
%type <obj> WHILE
%type <obj> LOOP
%type <obj> IFQUIT
%type <obj> IFNEVER
%type <obj> QUIT

/* Comparison Tokens */
%type <obj> EQUAL_COMP
%type <obj> UNEQUAL_COMP

/* Variables */
%type <obj> ID

/* Operator */
%type <obj> LOGIC_OP

/* Object for the tree */
%type <obj> seq_ifquit
%type <obj> seq_ifnever
%type <obj> seq_while
%type <obj> seq_else
%type <obj> seq_elseif
%type <obj> seq_if
%type <obj> sequence
%type <obj> inv_param2
%type <obj> inv_param
%type <obj> invocation
%type <obj> operator
%type <obj> factor
%type <obj> exp
%type <obj> value
%type <obj> values
%type <obj> init_array
%type <obj> asignation2
%type <obj> asignation
%type <obj> dim
%type <obj> array
%type <obj> line
%type <obj> lines
%type <obj> param_array
%type <obj> param
%type <obj> params
%type <obj> openBlock
%type <obj> block
%type <obj> block2
%type <obj> function2
%type <obj> parameters
%type <obj> function

%%

start		:	program;
program		:	/* Lambda */
			|	program function
			{
				tree.addNode($2);
			}; 

function	:	func_name ':' FUNCTION parameters function2
			{
				Node node= new Node("Function");
				node.addNode($<sval>1);
				node.addNode(":");
				node.addNode("function");
				node.addNode($4);
				node.addNode($5);
						
				$$= node;
				
			};

func_name	: ID
			{st.addFunction($<sval>1);};

parameters	:	/* Lambda */
			{	$$=null;	}
			/* Only params Input */
			|	params
			{
				Node node=new Node("Params_In");
				node.addNode($1);
				
				$$=node;
			}
			/* Params Input and Output */
			|	params START_OUTPUT_PARAM params
			{
				Node node=new Node("Parameters");
				node.addNode($1);
				node.addNode("->");
				node.addNode($3);
				
				$$=node;
			}
			/* Only Params Output */
			|	START_OUTPUT_PARAM params
			{
				Node node= new Node("Params_Out");
				node.addNode("->");
				node.addNode($2);
				
				$$=node;
			};
		
function2	:	';'
			{	$$= new Node(";");	}
			|	block
			{	$$=$1;	}; 

 
block		:	openBlock block2;
				{
					
					$$=$2; 		/* AAAAAAAAARRRRRRRRRRRRRRRREEEEEEEEEEGGGGGGGGGLLLLLLLLLLLAAAAAAAAAAAAARRRRRRRRRR? */
				}

openBlock	:	'{'	;	
			{	st.startBlock();	}
 

block2		:	lines '}'; 
			{	
				
				st.endBlock();
				
				Node node= new Node("Block");
				node.addNode("{");
				node.addNode($1);
				node.addNode("}");
				
				$$=node;
			};
		
params		:	param	
			{	$$=$1;	}
			|	params ',' param
			{
				Node node= new Node("Params");
				node.addNode($1);
				node.addNode(",");
				node.addNode($3);
				
				$$=node;
			}; 
			

param		:	ID ':' TYPE	param_array
			{
				st.addNode($<sval>1,$<sval>3);  
				
				Node node= new Node("Param");
				node.addNode($<sval>1);
				node.addNode(":");
				node.addNode($<sval>3);
				node.addNode($4);
				
				$$=node;				
			};
			
param_array	:	/* Lambda */
			{	$$=null;	}
			|	param_array '[' ']'
			{
				Node node= new Node("Param_Array");
				node.addNode($1);
				node.addNode("[");
				node.addNode("]");
				
				$$=node;
			};

			

lines		:	/* Lambda */
			{	$$=null;	}
			|	lines line
			{
				Node node= new Node("Lines");
				node.addNode($1);
				node.addNode($2);
				
				$$=node;
			};


line		:	ID ':' TYPE array asignation ';'
			{	
				st.addNode($<sval>1,$<sval>3);  
				Node node= new Node("Line");
				node.addNode($<sval>1);
				node.addNode(":");
				node.addNode($3);
				node.addNode($4);
				node.addNode($5);
				
				$$= node;
			}
			|	ID array asignation ';'
			{	
				Node node= new Node("Line");
				node.addNode($<sval>1);
				node.addNode($2);
				node.addNode(";");
				
				$$= node;
			}
			|	invocation ';'
			{
				Node node= new Node("Line");
				node.addNode($1);
				node.addNode(";");
				
				$$= node;
			}
			|	sequence 
			{
				$$= $1;
			}
			|	block
			{			
				$$= $1;
			};
			
			



array		:	/* Lambda */
			{	$$=null;	}
			|	array '[' dim ']'
			{
				Node node= new Node("Array");
				node.addNode($1);
				node.addNode(" [ ");
				node.addNode($3);
				node.addNode(" ] ");
				
				$$=node;
			}; 

dim			:	/* Lambda */
			{	$$=null;	}
			|	exp
			{	$$=$1;	};

asignation		:	/* Lambda */
			{	$$=null;	}
			|	'=' asignation2
			{
				Node node= new Node("Asignation");
				node.addNode("=");
				node.addNode($2);
				
				$$=node;
			};
		
asignation2 	: exp 
			{	$$=$1;	}
			| init_array
			{	$$=$1;	};
		
init_array 		:	'{' values '}'
			{
				Node node= new Node("Init_Array");
				node.addNode("{");
				node.addNode($2);
				node.addNode("}");
				
				$$=node;
			};

values		:	value 
			{	$$=$1;	}
			| 	values ',' value
			{	
				Node node= new Node("Values");
				node.addNode($1);
				node.addNode(",");
				node.addNode($3);
				
				$$=node;
			};
		
value			:	exp
			{	$$=$1;	} 
			|	init_array
			{	$$=$1;	};			
			

exp			:	exp operator factor
			{	
				Node node= new Node("Exp");
				node.addNode($1);
				node.addNode($2);
				node.addNode($3);
				
				$$=node;
			}
			|	'!' factor
			{	
				Node node= new Node("Exp");
				node.addNode("!");
				node.addNode($2);
				
				$$=node;
			}
			|	factor
			{	
				Node node= new Node("Exp");
				node.addNode($1);
				
				$$=node;
			};

		 

factor		:	'(' exp ')'
			{	
				Node node= new Node("Factor");
				node.addNode("(");
				node.addNode($2);
				node.addNode(")");
				
				$$=node;
			}

			|	INTEGER_NUM 
			{	
				Node node= new Node("Factor");
				node.addNode($<sval>1);
				
				$$=node;
			}
			| 	REAL_NUM 
			{	
				Node node= new Node("Factor");
				node.addNode($<sval>1);
				
				$$=node;
			}
			| 	STRING_TEXT 
			{	
				Node node= new Node("Factor");
				node.addNode($<sval>1);
				
				$$=node;
			}
			| 	TRUE 
			{	
				Node node= new Node("Factor");
				node.addNode($<sval>1);
				
				$$=node;
			}
			| 	FALSE
			{	
				Node node= new Node("Factor");
				node.addNode($<sval>1);
				
				$$=node;
			}
			|	invocation
			{	
				Node node= new Node("Factor");
				node.addNode($1);
				
				$$=node;
			}

			|	ID array;
			{
				Node node= new Node("Factor");
				node.addNode($<sval>1);
				node.addNode($2);
				
				$$=node;
			
			}

operator	:	'+'
			{	$$= new Node("+");	}
			|	'-'
			{	$$= new Node("-");	}
			|	'*'
			{	$$= new Node("*");	}
			|	'/'
			{	$$= new Node("/");	}
			|	'%'
			{	$$= new Node("%");	}
			|	LOGIC_OP
			{	$$= new Node($<sval>1);	}
			|	EQUAL_COMP
			{	$$= new Node($<sval>1);	}
			|	UNEQUAL_COMP
			{	$$= new Node($<sval>1);	};

invocation	:	ID '(' inv_param ')'
			{
				Node node= new Node("Invocation");
				node.addNode($<sval>1);
				node.addNode("(");
				node.addNode($3);
				node.addNode(")");
				
				$$=node;			
			}; 
			
inv_param	: 	/* Lambda */
			{	$$=null;	}
			|	inv_param2
			{	$$=$1;	}; 

inv_param2	: 	exp
			{	$$=$1;	}
			|	inv_param2 ',' exp
			{	
				Node node= new Node("Inv_Param");
				node.addNode($1);
				node.addNode(",");
				node.addNode($3);
				
				$$=node;
			}; 

/* Control sequence */
sequence	:	seq_if
			{	$$=$1;	}
			|	seq_while
			{	$$=$1;	};

seq_if		:	IF exp THEN block seq_elseif
			{	
				Node node= new Node("Seq_If");
				node.addNode("if");
				node.addNode($2);
				node.addNode("then");
				node.addNode($4);
				node.addNode($5);			
				
				$$=node;
			}; 
			
seq_elseif	:	seq_else
			{	$$=$1;	}
			/* Permite varios elseif anidados */
			|	ELSEIF exp block seq_elseif	
			{
				Node node= new Node("Seq_ElseIf");
				node.addNode("elseif");
				node.addNode($2);
				node.addNode($3);
				node.addNode($4);
				
				$$=node;
			};
			
seq_else	:	/* Lambda */
			{	$$=null;	}
			|	ELSE block
			{	
				Node node= new Node("Seq_Else");
				node.addNode("else");
				node.addNode($2);
				
				$$=node;
			};

seq_while	:	WHILE '(' exp ')' LOOP block seq_ifnever
			{
				Node node= new Node("Seq_While");
				node.addNode("while");
				node.addNode("(");
				node.addNode($3);
				node.addNode(")");
				node.addNode("loop");
				node.addNode($6);
				node.addNode($7);
				
				$$=node;
			};
			
seq_ifnever	:	IFNEVER block seq_ifquit
			{
				Node node= new Node("Seq_If_Never");
				node.addNode("ifnever");
				node.addNode($2);
				node.addNode($3);
				
				$$=node;
			}
			|	seq_ifquit
			{
				$$=$1;
			};
			
seq_ifquit	:	/* Lambda */
			{	$$=null;	}
			|	IFQUIT block
			{
				Node node= new Node("Seq_If_Quit");
				node.addNode("ifquit");
				node.addNode($2);
				
				$$=node;
			};



%%

  	protected Yylex lexer;
	protected Yytoken yytoken;
	public String func;
	public String varname;
	static SymbolTable st;
	static Tree tree;

private int yylex () {
    	int yyl_return = -1;
	try {
 
      	yylval = new ParserVal(0);
		yytoken= lexer.yylex();

	    	if(yytoken.m_index!= Token.EOF.getValue())
     		{
    			yyl_return = yytoken.m_index;
    		}
     		else
    		{
     			yyl_return =0;
	     		System.out.println("Se termino el archivo!!");
    		}
    }
    catch (IOException e) {
    	System.err.println("IO error :"+e);
    }
    	return yyl_return;
}


public void yyerror (String error) {
	System.err.println ("Error: " + error);
}


public Parser(Reader r) {
	lexer = new Yylex(r, this);
}
  
public void printSymbolTable(){
	st.printTable();
}

public void setYylval(ParserVal yylval) {
	this.yylval = yylval;
}
public ParserVal getYylval() {
	return yylval;
}
    



